#pragma once

#include <iostream>
#include <queue>
#include <pthread.h>
const int gcap=5;
template <class T>
class BlockQueue
{
public:
    BlockQueue(const int cap=gcap):_cap(cap)
    {
        pthread_mutex_init(&_mutex,nullptr);
        pthread_cond_init(&_consumerCond,nullptr);
        pthread_cond_init(&_productorCond,nullptr);

    }
    bool isFull(){ return _q.size() == _cap; }
    bool isEmpty() { return _q.empty(); }
    void push(const T &in)
    {
        //先加锁
        pthread_mutex_lock(&_mutex);
        while(isFull())//1.判断资源是否就绪 只能在临界区内判断 当前一定持有锁的
        {
            //2.要让线程休眠等待，不能持有锁：pthread_cond_wait有锁的释放功能
            //3.当线程醒来继续从临界区内部继续运行，从pthread_cond_wait处开始执行
            //pthread_cond_wait在醒来时又要重新申请锁，申请成功才会彻底返回
            pthread_cond_wait(&_productorCond,&_mutex);

        }
        _q.push(in);
        //生产者唤醒消费者（生产者如果push成功说明队列不为空，消费者可以消费）
        pthread_cond_signal(&_consumerCond);

        pthread_mutex_unlock(&_mutex);
    }
    void pop(T *out)//输出型参数
    {
         pthread_mutex_lock(&_mutex);
        while(isEmpty()) 
        {
            pthread_cond_wait(&_consumerCond, &_mutex);
        }
        *out = _q.front();
        _q.pop();
        //消费者唤醒生产（消费者如果pop成功说明队列不为满，生产者可以生产）
        pthread_cond_signal(&_productorCond);
        pthread_mutex_unlock(&_mutex);
    }
    ~BlockQueue()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_consumerCond);
        pthread_cond_destroy(&_productorCond);

    }
private:
    std::queue<T> _q;
    int _cap;//容量
     // 一把锁 生产和消费访问的是同一个queue&&queue被当做整体使用！
    pthread_mutex_t _mutex;
    //需要两个条件变量
    pthread_cond_t _consumerCond;   // 消费者对应的条件变量，阻塞队列空，wait
    pthread_cond_t _productorCond;  // 生产者对应的条件变量，阻塞队列满，wait
};